﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using Zhp.Auth.IService;
using Zhp.Common.Appsetting;

namespace Zhp.Auth
{
    public class CustomAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
    {
        IOnlineService onlineSvc;
        public CustomAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, IOnlineService onlineSvc) : base(options, logger, encoder)
        {
            this.onlineSvc = onlineSvc;
        }

        /// <summary>
        /// 已在JWT中做校验
        /// </summary>
        /// <returns></returns>
        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            string token = Context.Request.Query["token"];
            if (string.IsNullOrEmpty(token))
            {
                var jwtHandler = new JwtSecurityTokenHandler();
                var jwtOptions = AppSettingHelper.GetOptions<JwtOptions>();
                var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SigningKey));
                // 创建一个TokenValidationParameters对象，用于配置JWT验证的参数
                var tokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = signingKey,
                    ValidateIssuer = true,
                    ValidIssuer = jwtOptions.Issuer, //发行人
                    ValidateAudience = true,
                    ValidAudience = jwtOptions.Audience, //订阅人
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.FromSeconds(0),//时间偏移量，过期了还能用
                    RequireExpirationTime = true
                };
                // 验证JWT并获取ClaimsPrincipal对象
                ClaimsPrincipal principal = jwtHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken validatedToken);
                var vilidate = await jwtHandler.ValidateTokenAsync(token, tokenValidationParameters);
                if (vilidate.IsValid)
                {
                    var tokenId = vilidate.ClaimsIdentity.Claims.First(x => x.Type == JwtRegisteredClaimNames.Jti).Value;
                    var userId = vilidate.ClaimsIdentity.Claims.First(x => x.Type == ClaimTypes.Sid).Value;
                    var isOnline = onlineSvc.IsOnline(tokenId, userId);
                    if (!isOnline.IsOnline)
                    {
                        return await Task.FromResult(AuthenticateResult.Fail(new SecurityTokenInvalidLifetimeException(isOnline.Message)));
                    }
                    else
                    {
                        var ticket = new AuthenticationTicket(principal, UrlTokenDefaults.AuthenticationScheme);
                        return await Task.FromResult(AuthenticateResult.Success(ticket));
                    }
                }
                else
                {
                    return await Task.FromResult(AuthenticateResult.Fail("ticket"));
                }
            }
            //获取token并且解析出token，判断在在线用户中是否存在
            return await Task.FromResult(AuthenticateResult.Fail("登录过期，请重新登录！"));
        }
    }

    public class UrlTokenDefaults
    {
        public const string AuthenticationScheme = "UrlTokenScheme";
        public const string AuthenticationDisplayScheme = "UrlTokenDisplayScheme";
    }
}
